/**
 * @file StreamAnalyser.h
 *
 * This file defines the stream analyser API
 *
 * @author Luc Fourestier
 * @date 2009
 */

#ifndef STREAMANALYSER_H_
#define STREAMANALYSER_H_

#include "Global.h"

#include "PAT.h"
#include "PMT.h"
#include "CircBuff.h"

#include <stdio.h>
#include <sys/time.h>
#include <pthread.h>
#include <arpa/inet.h>

// Errors
#define SA_ERROR_BAD_PARAM       1	//!< Incorrect parameters
#define SA_ERROR_CANNOT_ALLOCATE 2	//!< Cannot create/allocate object required by the StreamAnalyzer
#define SA_ERROR_CANNOT_ANALYZE	 3	//!< Cannot analyze the chunk (Not a TS for instance)
#define SA_ERROR_CANNOT_DUMP	 4	//!< Cannot dump into a file (file write error)
#define SA_ERROR_CIRCBUFF_ERROR	 5	//!< Cannot read/write from circular buffer
#define SA_ERROR_CANNOT_OPEN_FILE 6 //!< Cannot open file (info, jitter files...)
#define SA_ERROR_SOCKET_ERROR    7  //!< Cannot open/read/write from sockets

// Defines
#define SA_MAX_PROGRAM PAT_MAX_PROGRAM_DESC
#define SA_MAX_NAME_LENGTH MAX_NAME_LENGTH

/**
 * The tagging structure
 */
typedef struct Tag_s
{
	unsigned int ReadyToPlay;		//!< The chunk can be played out by the StreamPlayer (after analysis)
	struct timeval ReceptionTime; 	//!< Time when chunk has been received
	struct timeval TimeToSend; 		//!< Time when to send the chunk
	unsigned int ChunkIsLast;		//!< That chunk is the last of the stream (when reading a file for instance)
} Tag_t;

/**
 * Specify the option to be used while treating incoming stream.
 */
typedef struct SA_Option_s
{
	char PcrFileName[SA_MAX_NAME_LENGTH];  	//!< The name of the PCR file
	char TableFileName[SA_MAX_NAME_LENGTH];  	//!< The name of the SI table file
	unsigned int MaxBufferSize; 				//!< Maximum size in bytes of the circular buffer element (ex: 1500)
	unsigned int MaxBufferNumber; 			    //!< Maximum number of buffer we can remember before analysis
	struct timeval ReferenceTime; 				//!< The reference time for timestamps
} SA_Option_t;

/**
 * The stream analyzer info structure.
 */
typedef struct SA_StreamAnalyzer_s
{
	unsigned char Magic; 						//!< Magic number (internal use)
	SA_Option_t Options; 						//!< Init options
	unsigned long long TotalPacketNumber; 		//!< Total number of treated packets
	PAT_t PAT;									//!< the PAT found
	unsigned long long TotalPATNumber;			//!< Total number of PAT seen
	PMT_t PMT[SA_MAX_PROGRAM]; 					//!< the PMTs found
	unsigned long long TotalPMTNumber[SA_MAX_PROGRAM]; //!< Total number of PMT seen
	FILE * PcrFile;    						    //!< PCR file pointer
	FILE * TableFile;    						//!< SI table file pointer
	double Duration;   							//!< Current duration of the stream in seconds
	CircBuff_t * CircBuffer;					//!< The circular buffer where are stored the incoming stream chunks
	unsigned char ThreadLoop;					//!< The infinite loop of the analyzer thread
	pthread_t AnalyzerThreadID;					//!< The analyzer thread ID
	unsigned long long TotalPacketError;        //!< The number of erroneous packets in the stream
	unsigned long long TotalCircError;        	//!< The number of circular buffer error
	unsigned long long LastPCR;				    //!< The last PCR stamps seen in the stream
	unsigned long long LastPCRPckNumber; 		//!< The packet number of the last PCR
	struct timeval LastPCRTime;					//!< The timestamp of the last PCR
	unsigned int LastPCROffset;					//!< The offset of the PCR packet in the chunk.
	unsigned char NewPCRFound;				    //!< Found new PCR!
	unsigned long long NewPCR;				    //!< The new PCR stamps seen in the stream
	unsigned long long NewPCRPckNumber; 		//!< The packet number of the new PCR
	struct timeval NewPCRTime;					//!< The timestamp of the new PCR
	unsigned int NewPCROffset;					//!< The offset of the PCR packet in the chunk.
	unsigned long long PCRDelta;				//!< Calculated difference between NewPCR and LastPCR
	unsigned long long TotalPCRNumber; 			//!< The total PCR packet number
	unsigned int AvgBitrate;					//!< The bit rate in bits per seconds
	unsigned int InstantBitrate;					//!< The bit rate in bits per seconds

#ifdef DEBUG_SA_PROFILING
	struct timeval TotalPassDuration;			//!< The sum of all pass duration (a pass is one thread round)
	unsigned long long passCount;				//!< The number of pass
	unsigned long long passError;				//!< The number of pass error
#endif
} SA_StreamAnalyzer_t;

/**
 * @brief Create a StreamAnalyzer
 */
int SA_Create(SA_StreamAnalyzer_t ** SA, SA_Option_t Options);

/**
 * @brief Delete the StreamAnalyzer
 */
int SA_Delete(SA_StreamAnalyzer_t * SA);

/**
 * @brief Print the StreamAnalyzer
 */
int SA_Print(SA_StreamAnalyzer_t * SA, char * Name, int Level, FILE * Output);

#endif /* STREAMANALYSER_H_ */
